// import export 外部模块，就是隔离多个不同的文件

// namespace 内部模块  隔离同一个文件的

// let obj = {
//   Zoo: function () {
//     class Dog {}
//     return Dog;
//   },
//   Home: function () {
//     class Dog {}
//     return Dog;
//   },
// };

// import { Zoo, Home } from "./module/dog";
// console.log(Zoo.Dog, Home.Dog, Zoo.a, Home.b, Zoo.House.Dog);
// 业务逻辑中使用不到

// 在声明文件中 可以通过namespace来进行一系列扩展 (不是自己写，一般都是生成)

// 扩展类 、 函数、 枚举 扩展的命名空间必须写在这些声明的下面

class Zoo {}
namespace Zoo {
  export let a = 1; // static a =1
}

function counter() {
  return counter.count++;
}
// counter.count = 0
namespace counter {
  export let count = 0;
}

enum Seson {} // Spring = "春";
namespace Seson {
  export let Spring = "春";
}
Seson.Spring;

// 声明文件、 装包、拆包 、 类型体操
// (keyof typeof)
// never 所有类型的子类型 （底端类型） 我不想要的就是never, 完整性保护
// 字面量类型
// 基础类型 （基础类型 string, number ,boolean null undefied void ）
// 数组、元组、枚举
// 非基础类型 object
// 包装类型
// any unknown
// 联合类型、 交叉类型  （断言） as ！?  双重断言

// 函数（签名）： 参数、返回值、可选的？ 默认值= 剩余参数... this的问题  函数的重载（类型重载）
// 逆变和协边 {concat():void} 而不熟  {concat:()void}   传父 返子

// 类 修饰符 private protected public readonly  (private constructor) 子类重写方法的问题
// 类型兼容 原型方法和实例方法的声明。  抽象类 , 类类型，构造函数类型

// 接口： 可选？  readonly 任意类型 ，可索引接口  extends implements
// type 和 interface的区别

// 泛型 （坑位）， 用的时候传递类型 （默认泛型，泛型约束）
// 条件类型 （子extend父） 映射类型  （子：子类型、子结构，父：父类型、父结构）
// 分发的问题 有好有坏 （需要禁用分发的时候  T & {}   [T]）

// extract exclude
// Partial Readonly...
// Pick Omit Record
// infer的作用

// 兼容性， 内置的类型推导 （右边复制可以推导类型，函数提供上下文可以推导类型， 返回值也可以推导）
// 类型保护 typeof instanceof in 可辨识类型、 is

// 重映射 + 自定义类型
// ...........................................................................................................
{
  //模块和命名空间
  // 模块 叫外部模块,命名空间 叫内部模块(用的比较少)
  //目前我们主要采用 es6 的模块来创建作用域(按照文件)来划分的、

  // 文件里有import、export，会在当前文件生成独立作用域

  // import a from "./a";
  let a = require("./a");
  import a = require("./a");
  console.log(a);

  //常见的模块规范 esm(es6模块)amd(define)cmd(commonjs 规范)
  // esm(es6模块)可以转化成amd(define)或者cmd(commonjs 规范)
  //commonjs 规范 不能转化成  amd规范
  //commonjs 规范  不能转化成  esm规范

  // AMD ，module改成AMD 需要在tsconfig.json中增加files: ['./src/index.ts']
  // commonjs ，module改成commonjs 运行时package.json type;删除掉
  // npx tsc src/index.ts  执行node_modules，bin目录下的tsc命令

  // commonjs和import 混用
  // 导出文件中的 export = 2；编译后会变为module.exports =2
  // 在引入文件位置，可以import a from "./a";但需要在编译后的文件删除变量a后的default，才能访问a
  //   import a = require("./a");
  //  export = 2；import a = require("./a");只会在申明文件时用到

  //   "esModuleInterop": true,可以 commonjs和import 混用

  // 模块最好不要混，用在eS 6下引用common js规范的模块不好
  // 在ts语法中，有一种模块化方式 export = 2；import a = require("./a");只会在声明文件时用到

  // 开发全部采用 import export

  // 写声明文件的时候，如果模块是commonis，或者想快速的导出一个值可以采用ts语法
  // 记住tsconfig.json module改成commonjs
  // export = 'abc'
  // import x= require("xxxx")
  // 使用时可以采用es模块的方式导入

  //  tsconfig.json target:'ES2018' 打包方法
  // tsconfig.json module改成commonjs 生成模块

  // ............................................................................................
  /*
  //  Zoo空值无法访问，会报错
  namespace Zoo { }
  console.log(Zoo);
   */
  /*
  // 命名空间可以导出，一个文件同名的所有的namespace，必须一起导出
  // 命名空间重名会合并 Zoo
  export namespace Zoo {
    export let dog: string = "动物园的狗";
  }
  // 命名空间重名会合并 Zoo
  export namespace Zoo {
    export let cat: string = "动物园的猫";
  }
  export namespace Home {
    export let dog: string = "家里的猫";
  }
 */
  // 命名空间可以修饰类，扩展类
  export class Zoo {
    static monkey = "动物园的猴子";
  }
  // 命名空间重名会合并 Zoo
  namespace Zoo {
    export let dog: string = "动物园的狗";
  }
  // 命名空间重名会合并 Zoo
  namespace Zoo {
    export let cat: string = "动物园的猫";
  }
  namespace Home {
    export let dog: string = "家里的猫";
    // 命名空间可以嵌套
    export namespace Company {
      export let cat: string = "公司的猫";
    }
  }
  /*   
  // 上面代码的编译结果
  class Zoo {}
  Zoo.monkey = "动物园的猴子";
  (function (Zoo) {
    Zoo.dog = "动物园的狗";
  })(Zoo || (Zoo = {}));
  (function (Zoo) {
    Zoo.cat = "动物园的猫";
  })(Zoo || (Zoo = {}));
  var Home;
  (function (Home) {
    Home.dog = "家里面的狗";
    (function (x) {
      Company.cat = "公司的猫";
    })(Home.Company || (Home.Company = {}));
  })(Home || (Home = {})); 
  
  */

  //  Zoo Home有值才能访问
  console.log(Zoo.dog, Zoo.cat, Zoo.monkey);
  console.log(Home.dog);
  console.log(Home.Company.cat);

  // 命名空间可以修饰函数，扩展函数
  function counter() {
    return counter.count++;
  }
  // counter.count = 0
  namespace counter {
    // 额外不需要暴露给外面的扩展
    // .....................................
    // 需要暴露给外面的扩展;
    export let count = 0;
  }
  // 命名空间，做扩展比较多，只要是对象都可以做扩展，模块用import和export

  // 例如枚举扩展，注意 enum ROLE {}前，不能加const  加const的枚举最后不编译
  enum ROLE {}
  namespace ROLE {
    export let user = 1;
  }

  ROLE.user;
  // 命名空间主要就是给对象扩展属性，可以做到产生一个作用域
}
